#include "HashUtility.h"
#include <fstream>
#include <sstream>
#include <iomanip>
#include <crypto++/sha.h>
#include <crypto++/base64.h>

namespace etu {
namespace common {

std::string HashUtility::hashString(const std::string& str) {
    std::istringstream strStream;
    strStream.str(str);

    return HashUtility::hashStream(strStream);
}

std::string HashUtility::hashBuffer(unsigned char* buffer, int length) {
    std::ostringstream byteStream;

    for(int i = 0; i < length; i++) {
       byteStream << buffer[i];
    }

    std::istream inputStream(byteStream.rdbuf());

    return HashUtility::hashStream(inputStream);
}

std::string HashUtility::hashFile(const std::string& filePath) {
    std::string ret;
    std::ifstream fileStream;
    
    fileStream.open(filePath.c_str(), std::ios::binary);
    ret = HashUtility::hashStream(fileStream);
    fileStream.close();

    return ret;
}

std::string HashUtility::hashStream(std::istream& input) {
    CryptoPP::SHA256 hash;
    byte sha256[CryptoPP::SHA256::DIGESTSIZE];
    int length = 0;
    char * buffer;

    input.seekg(0, std::ios::end);
    length = input.tellg();
    input.seekg(0, std::ios::beg);

    buffer = new char[length];

    input.read(buffer, length);

    hash.CalculateDigest(sha256, (unsigned char *) buffer, length);
    std::ostringstream ret;

    for (int i = 0; i < CryptoPP::SHA256::DIGESTSIZE; i++) {
        ret << std::hex << std::setfill('0') << std::setw(2) <<
                (unsigned short) (sha256[i]);
    }

    delete[] buffer;

    return ret.str();
}

}
}
